﻿using CommonModel.Field;
using GXRTBTC.PublicClassLibrary.Field;
using GXRTBTC.PublicClassLibrary.Util;
using Microsoft.Extensions.Logging;
using NewLife.Log;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static CommonModel.Model.DataTypeDll;
using static CommonModel.Util.StructUtil;

namespace CommonModel.Util
{
    public class CodeUtil
    {
        /// <summary>
        /// 命令码解析，其中300W/1000W是命令码解析，但是与其他常见的不同，需要通过参数判别
        /// </summary>
        /// <param name="doc"></param>
        /// <param name="data"></param>
        /// <param name="DeviceModelType"></param>
        /// <returns></returns>
        public static Dictionary<string, object> ByteParseViaCode(SchemaDocument doc, byte[] data, string DeviceModelType = "")
        {
            Dictionary<int, SchemaDictionary> schemaDictionary = doc.fieldDictionary;//读取的XML模板的字段字典
            Dictionary<string, object> parsedDataDictionary = new Dictionary<string, object>();//解析后的字典

            //将数据按照XML配置文件截取后的字典
            Dictionary<string, List<CodeField>> dictDictionary;
            if (DeviceModelType == "M_300_1000")
            {
                int currentCursor = 0;
                //将数据解析到命令码字典对照表中 300/1000W数字电视发射机类型
                dictDictionary = parseCodes300Or1000(data, currentCursor, new Dictionary<string, List<CodeField>>());
            }
            else
            {
                //将数据解析到命令码字典对照表中
                dictDictionary = parseCodes(data);
            }

            //解析
            parseDictionary(schemaDictionary, dictDictionary, parsedDataDictionary);
            return parsedDataDictionary;
        }

        /// <summary>
        /// 根据schemaDictionary解析字段
        /// 逐个对照解析字典进行命令码的解析
        /// </summary>
        /// <param name="schemaDictionary">解析规则字典</param>
        /// <param name="dictDictionary">命令码与数据对照字典</param>
        /// <param name="parsedDataDictionary"></param>
        public static void parseDictionary(Dictionary<int, SchemaDictionary> schemaDictionary, Dictionary<string, List<CodeField>> dictDictionary, Dictionary<string, object> parsedDataDictionary)
        {
            for (int i = 0; i < schemaDictionary.Count; i++)
            {
                SchemaDictionary schema = schemaDictionary[i];

                //如果是普通的字段, 且不是字节位标识 bit 字段
                if (!schema.isNode)
                {
                    parseField(schema, dictDictionary, parsedDataDictionary);
                }
                //如果是字段集
                else
                {
                    DataType datype = schema.type;
                    string paraCode = schema.code;
                    int looper;
                    string name = schema.name;

                    switch (datype)
                    {
                        //位状态结构体, 低位在前高位在后
                        case DataType.BITARRAY:
                            if (!dictDictionary.ContainsKey(paraCode))
                            {
                                continue;
                            }
                            looper = getLooper(schema, parsedDataDictionary);
                            parsedDataDictionary.Add(name, new List<Dictionary<string, object>>());
                            for (int counter = 0; counter < looper; counter++)
                            {
                                ((List<Dictionary<string, object>>)parsedDataDictionary[name]).Add(new Dictionary<string, object>());
                                try
                                {
                                    parseBitArray(dictDictionary, schema, ((List<Dictionary<string, object>>)(parsedDataDictionary)[name])[counter]);
                                }
                                catch(Exception e)
                                {
                                    CommonUtil.mLogger.LogError("parseDictionary函数Code结构体parseBitArray()解析出错" + e + ",出错的name：" + name);
                                }
                            }

                            break;
                        //结构体, loop循环结构体
                        //就目前来说，STRUCTLIST和STRUCT是一样处理的，只有STRUCTLOOP比较特殊
                        case DataType.STRUCT:
                            try
                            {
                                parseCodeStruct(dictDictionary, schema, parsedDataDictionary);
                            }
                            catch(Exception e)
                            {
                                CommonUtil.mLogger.LogError("parseDictionary函数Code结构体parseCodeStruct()解析出错" + e + ",出错的name：" + name);
                            }
                            
                            break;
                        case DataType.STRUCTLIST:
                            try
                            {
                                parseCodeStruct(dictDictionary, schema, parsedDataDictionary);
                            }
                            catch (Exception e)
                            {
                                CommonUtil.mLogger.LogError("parseDictionary函数Code结构体parseCodeStruct()解析出错" + e + ",出错的name：" + name);
                            }

                            break;
                        //20230329 杨世旺新增，针对类似于数字电视1+1切换器0x0706的时间表循环的
                        //如0x0160，根据最大开关机条数0x0167的数据N，乘以6分隔开，获取每一段时间
                        case DataType.STRUCTLOOP:
                            try
                            {
                                parseCodeStructLoop(dictDictionary, schema, parsedDataDictionary);
                            }
                            catch (Exception e)
                            {
                                CommonUtil.mLogger.LogError("parseDictionary函数Code结构体parseCodeStructLoop()解析出错" + e + ",出错的name：" + name);
                            }

                            break;
                        default:
                            break;
                    }
                }

            }
        }

        /// <summary>
        /// 解析成单独的字段
        /// </summary>
        /// <param name="schField"></param>
        /// <param name="dictDictionary"></param>
        /// <param name="parsedDataDictionary"></param>
        public static void parseField(SchemaDictionary schField, Dictionary<string, List<CodeField>> dictDictionary, Dictionary<string, object> parsedDataDictionary)
        {
            string paraCode = schField.code;
            List<CodeField> codeFieldList;

            //从 dict 中取出对应的命令码的值作为待解析的值
            // 如果在字典中找到, 则解析, 否则忽略
            if (dictDictionary.ContainsKey(paraCode))
            {
                codeFieldList = dictDictionary[paraCode];
                if (codeFieldList.Count > 0)
                {
                    string value = "";
                    CodeField codeField = codeFieldList[0];
                    try
                    {
                        value = BytesParseToTypeString.ParseValue(schField.type, codeField.value);//开始解析
                    }
                    catch (Exception e)
                    {
                        CommonUtil.mLogger.LogError("parseField函数解析单独的字段出错，出错字段是："+paraCode+ ",出错问题是："+e);
                    }
                    //20221101 ysw 添加元素有多个的才删除的判断
                    if (codeFieldList.Count > 1)
                    {
                        codeFieldList.Remove(codeFieldList[0]); // 取出后立即删除。因为若参数码有多个值的，要删掉，方便下一次取值
                        dictDictionary[paraCode] = codeFieldList;   // 更新字典
                    }
                    parsedDataDictionary.Add(schField.name, value);
                }
            }
            else
            {
                return;
            }
        }

        /// <summary>
        /// 解析成字节长度结构体，循环
        /// </summary>
        /// <param name="dictDictionary"></param>
        /// <param name="subSchDictionary"></param>
        /// <param name="parsedDataDictionary"></param>
        public static void parseCodeStruct(Dictionary<string, List<CodeField>> dictDictionary, SchemaDictionary subSchDictionary, Dictionary<string, object> parsedDataDictionary)
        {
            int looper = getLooper_code(subSchDictionary, parsedDataDictionary);
            string pname = subSchDictionary.name;
            Dictionary<int, SchemaDictionary> subSchFieldDictionary = subSchDictionary.fieldDictionary;
            parsedDataDictionary.Add(pname, new List<Dictionary<string, object>>());
            for (int counter = 0; counter < looper; counter++)
            {
                try
                {
                    //先把父名字存入
                    ((List<Dictionary<string, object>>)(parsedDataDictionary)[pname]).Add(new Dictionary<string, object>());
                    //递归
                    parseDictionary(subSchFieldDictionary, dictDictionary, ((List<Dictionary<string, object>>)(parsedDataDictionary)[pname])[counter]);
                }
                catch (Exception e)
                {
                    CommonUtil.mLogger.LogError("在循环解析字节结构体parseCodeStruct函数中，函数解析失败：" + pname + ",报错信息：" + e);
                }
            }

            //空节点移除
            if (((List<Dictionary<string, object>>)(parsedDataDictionary)[pname]).Count > 0)
            {
                int count = 0;
                foreach (var child in ((List<Dictionary<string, object>>)(parsedDataDictionary)[pname]))
                {
                    count = child.Count;
                }

                if (count == 0)
                {
                    parsedDataDictionary.Remove(pname);
                }
            }
        }

        /// <summary>
        /// 解析成字节长度结构体LIST，循环
        /// </summary>
        /// <param name="dictDictionary"></param>
        /// <param name="subSchDictionary"></param>
        /// <param name="parsedDataDictionary"></param>
        public static void parseCodeStructLoop(Dictionary<string, List<CodeField>> dictDictionary, SchemaDictionary subSchDictionary, Dictionary<string, object> parsedDataDictionary)
        {
            int looper = getLooper_code(subSchDictionary, parsedDataDictionary);
            string pname = subSchDictionary.name;
            Dictionary<int, SchemaDictionary> subSchFieldDictionary = subSchDictionary.fieldDictionary;
            parsedDataDictionary.Add(pname, new List<Dictionary<string, object>>());

            if (!dictDictionary.ContainsKey(subSchDictionary.code) || dictDictionary[subSchDictionary.code].Count == 0)
            {
                return;
            }

            int sumLen = 0;
            for (int i = 0; i < subSchFieldDictionary.Count; i++)
            {
                SchemaDictionary schema = subSchFieldDictionary[i];
                sumLen += schema.size;
            }

            for (int counter = 0; counter < looper; counter++)
            {
                try
                {
                    byte[] data = dictDictionary[subSchDictionary.code][0].value;

                    //获取总长度，并将name赋值到code
                    int currentCursor = 0;
                    for (int i = 0; i < subSchFieldDictionary.Count; i++)
                    {
                        SchemaDictionary schema = subSchFieldDictionary[i];
                        schema.code = schema.name;

                        CodeField codeField = new CodeField
                        {
                            code = schema.code,
                            value = data.Skip(currentCursor + sumLen * counter).Take(schema.size).ToArray()
                        };
                        if (!dictDictionary.ContainsKey(schema.code))
                        { 
                            dictDictionary.TryAdd(schema.code, new());
                        }
                        dictDictionary[schema.code] = new() { codeField };
                        currentCursor += schema.size;
                    }

                    //先把父名字存入
                    ((List<Dictionary<string, object>>)(parsedDataDictionary)[pname]).Add(new Dictionary<string, object>());
                    //递归
                    parseDictionary(subSchFieldDictionary, dictDictionary, ((List<Dictionary<string, object>>)(parsedDataDictionary)[pname])[counter]);
                }
                catch (Exception e)
                {
                    CommonUtil.mLogger.LogError("在循环解析字节结构体parseCodeStruct函数中，函数解析失败：" + pname + ",报错信息：" + e);
                }
            }

            //空节点移除
            if (((List<Dictionary<string, object>>)(parsedDataDictionary)[pname]).Count > 0)
            {
                int count = 0;
                foreach (var child in ((List<Dictionary<string, object>>)(parsedDataDictionary)[pname]))
                {
                    count = child.Count;
                }

                if (count == 0)
                {
                    parsedDataDictionary.Remove(pname);
                }
            }
        }

        /// <summary>
        /// 获取结构体数组的长度
        /// </summary>
        /// <param name="schDictionary">结构体解析字典</param>
        /// <param name="parsedDataDictionary"></param>
        /// <returns>字典中实际的loop属性值, 即数组个数</returns>
        public static int getLooper_code(SchemaDictionary schDictionary, Dictionary<string, object> parsedDataDictionary)
        {
            // TODO Auto-generated method stub
            string loopStr = schDictionary.loop;
            string loopValueStr;
            int loop = 1;
            if (loopStr == "0")
            {
                return -1;//表示不解析该字段
            }
            if (null == loopStr || loopStr.Equals(""))
            {
                loopStr = "1";
            }
            //正则判断是否是数字
            string regex = "^(-?[0-9]*[.]*[0-9]{0,3})$";
            /**
             * 如果是关联字段获取数组个数
             */
            if (Regex.IsMatch(loopStr, regex))
            {
                loopValueStr = loopStr;
                loop = Convert.ToInt32(loopValueStr);
            }
            else
            {
                if (parsedDataDictionary.ContainsKey(loopStr))
                { 
                    // 从已经解析的parsedDataDictionary中取出对应的值
                    loopValueStr = parsedDataDictionary[loopStr].ToString();
                    loop = Convert.ToInt32(loopValueStr);
                }
                else
                {
                    //typeof(List<>).Name
                    foreach (string key in parsedDataDictionary.Keys)
                    {
                        if (parsedDataDictionary[key] != null && parsedDataDictionary[key].GetType().Name.Equals(typeof(List<>).Name))
                        {
                            List<Dictionary<string, object>> listVal = (List<Dictionary<string, object>>)parsedDataDictionary[key];
                            foreach (Dictionary<string, object> dictVal in listVal)
                            {
                                if (dictVal.ContainsKey(loopStr))
                                {
                                    // 从已经解析的parsedDataDictionary中取出对应的值
                                    loopValueStr = parsedDataDictionary[loopStr].ToString();
                                    loop = Convert.ToInt32(loopValueStr);
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            return loop;
        }

        /// <summary>
        /// 解析成字节位结构体
        /// </summary>
        /// <param name="dictDictionary"></param>
        /// <param name="subSchDictionary"></param>
        /// <param name="parsedDataDictionary"></param>
        public static void parseBitArray(Dictionary<string, List<CodeField>> dictDictionary, SchemaDictionary subSchDictionary, Dictionary<string, object> parsedDataDictionary/*, ref int currentCursor, ref int currentParsedIndex*/)
        {
            string paraCode = subSchDictionary.code;
            List<CodeField> codeFieldList = dictDictionary[paraCode];

            // 如果在字典中找到, 则解析, 否则忽略
            if (codeFieldList.Count > 0 && null != codeFieldList[0])
            {          
                byte[] bitArray = TransForm.bytesToBitArray(codeFieldList[0].value);
                codeFieldList.Remove(codeFieldList[0]);         // 取出后立即删除。因为若参数码有多个值的，要删掉，方便下一次取值
                dictDictionary[paraCode] = codeFieldList;  // 更新字典
                Dictionary<int, SchemaDictionary> schFieldDictionary = subSchDictionary.fieldDictionary;
                // 设置字节位解析位置
                int cursor = 0;

                for (int i = 0; i < schFieldDictionary.Count; i++)
                {
                    SchemaDictionary fieldSch = schFieldDictionary[i];

                    // 根据 size 值截取字节位
                    int size = fieldSch.size;
                    int newCursor = cursor + size;

                    if (newCursor > bitArray.Length)
                    {
                        // 超出字节位长度, 则继续
                        continue;
                    }

                    string name = fieldSch.name;
                    string value = "";
                    // 一位一位进行转换, 然后再组合成字符串
                    byte[] data = new byte[size];
                    for (int idx = 0; idx < size; idx++)
                    {
                        data[size - idx - 1] = bitArray[cursor + idx];
                    }
                    try
                    {
                        value = BytesParseToTypeString.ParseValue(DataType.BIT, data);
                    }
                    catch (Exception e)
                    {
                        CommonUtil.mLogger.LogError("解析bitarray出错:" + name + ",报错信息：" + e);
                    }
                    cursor = newCursor; //20211231 ysw发现bug，新增此行
                    parsedDataDictionary.Add(name, value);
                }
            }
        }

        /// <summary>
        /// 对 bitarray结构进行解析
        /// 2020/11/16 likangfu 增加子字段为多个字节位组合的情况解析
        /// </summary>
        /// <param name="schDictionary">解析字典</param>
        /// <param name="data">数据</param>
        public static void parseBitArrayDictionary(SchemaDictionary schDictionary, /*SegmentData parsedSeg, */byte[] data)
        {
            // TODO Auto-generated method stub
            byte[] bitArray = TransForm.bytesToBitArray(data);
            Dictionary<int, SchemaDictionary> schFieldDictionary = schDictionary.fieldDictionary;
            Dictionary<string, object> parsedDataDictionary = new Dictionary<string, object>();
            // 设置字节位解析位置
            int cursor = 0;

            for (int i = 0; i < schFieldDictionary.Count; i++)
            {
                SchemaDictionary fieldSch = schFieldDictionary[i];

                // 根据 size 值截取字节位
                int size = fieldSch.size;
                int newCursor = cursor + size;

                if (newCursor > bitArray.Length)
                {
                    // 超出字节位长度, 则继续
                    continue;
                }

                string name = fieldSch.name;
                StringBuilder value = new StringBuilder();

                for (int idx = 0; idx < size; idx++)
                {
                    // 一位一位进行转换, 然后再组合成字符串
                    byte[] datax = new byte[1];
                    datax[idx] = bitArray[cursor + idx];
                    try
                    {
                        value.Append(BytesParseToTypeString.ParseValue(DataType.BYTE, datax));
                    }
                    catch (Exception e)
                    {
                        CommonUtil.mLogger.LogError("parseBitArrayDictionary函数解析bitarray出错" + name+",报错信息："+e);
                    }
                }

                cursor = cursor + size;
                parsedDataDictionary.Add(name, value.ToString());

            }
        }

        /// <summary>
        /// 将数据解析到命令码字典对照表中 通用类型
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static Dictionary<string, List<CodeField>> parseCodes(byte[] data)
        {
            // 设置开始游标
            int currentCursor = 28;//28位帧头信息
            Dictionary<string, List<CodeField>> fieldDictionary = new Dictionary<string, List<CodeField>>();
            // 设备ID
            byte[] devidbyte = data.Skip(currentCursor).Take(1).ToArray();
            currentCursor = currentCursor + 1;
            CodeField idCodeField = new CodeField
            {
                code = "devid",
                value = devidbyte
            };
            List<CodeField> idCodeFieldList = new List<CodeField>();
            idCodeFieldList.Add(idCodeField);
            fieldDictionary.Add("devid", idCodeFieldList);

            // 功能码
            byte[] funCodebyte = data.Skip(currentCursor).Take(1).ToArray();
            currentCursor = currentCursor + 1;
            CodeField funCodeField = new CodeField
            {
                code = "funcode",
                value = funCodebyte
            };
            List<CodeField> funCodeFieldList = new List<CodeField>();
            funCodeFieldList.Add(funCodeField);
            fieldDictionary.Add("funcode", funCodeFieldList);

            // 数据长度
            byte[] datlbyte = data.Skip(currentCursor).Take(2).ToArray();
            currentCursor = currentCursor + 2;
            CodeField lenField = new CodeField
            {
                code = "datalength",
                value = datlbyte
            };
            List<CodeField> lenFieldList = new List<CodeField>();
            lenFieldList.Add(lenField);
            fieldDictionary.Add("datalength", lenFieldList);

            while (currentCursor < data.Length - 2)
            {
                byte[] parabyte = data.Skip(currentCursor).Take(2).ToArray();//参数序号
                currentCursor = currentCursor + 2;
                string paracode = TransForm.ByteToHexString(parabyte);

                byte[] paraLbyte = data.Skip(currentCursor).Take(1).ToArray();//参数长度
                currentCursor = currentCursor + 1;
                int paraLen = TransForm.ByteToUint8(paraLbyte);

                byte[] paravalue = data.Skip(currentCursor).Take(paraLen).ToArray(); //参数值
                currentCursor = currentCursor + paraLen;
                CodeField codeField = new CodeField
                {
                    code = paracode,
                    value = paravalue
                };

                if (fieldDictionary.ContainsKey(paracode))
                {
                    fieldDictionary[paracode].Add(codeField);
                }
                else
                {
                    fieldDictionary.Add(paracode, new List<CodeField>() { codeField });
                }
            }
            return fieldDictionary;
        }


        /// <summary>
        /// 将数据解析到命令码字典对照表中 300/1000W数字电视发射机类型
        /// </summary>
        /// <param name="data"></param>
        /// <param name="currentCursor"></param>
        /// <param name="fieldDictionary"></param>
        /// <returns></returns>
        public static Dictionary<string, List<CodeField>> parseCodes300Or1000(byte[] data, int currentCursor, Dictionary<string, List<CodeField>> fieldDictionary)
        {
            // 起始字
            byte[] startFlagbyte = data.Skip(currentCursor).Take(1).ToArray();
            currentCursor = currentCursor + 1;
            CodeField startFlagField = new CodeField
            {
                code = "startflag",
                value = startFlagbyte
            };
            List<CodeField> startFlagFieldList = new List<CodeField>();
            startFlagFieldList.Add(startFlagField);
            fieldDictionary.Add("startflag", startFlagFieldList);

            // 设备地址
            byte[] devidbyte = data.Skip(currentCursor).Take(1).ToArray();
            currentCursor = currentCursor + 1;
            CodeField idCodeField = new CodeField
            {
                code = "devid",
                value = devidbyte
            };
            List<CodeField> idCodeFieldList = new List<CodeField>();
            idCodeFieldList.Add(idCodeField);
            fieldDictionary.Add("devid", idCodeFieldList);

            // 指令码
            byte[] funCodebyte = data.Skip(currentCursor).Take(1).ToArray();
            currentCursor = currentCursor + 1;
            CodeField funCodeField = new CodeField
            {
                code = "funcode",
                value = funCodebyte
            };
            List<CodeField> funCodeFieldList = new List<CodeField>();
            funCodeFieldList.Add(funCodeField);
            fieldDictionary.Add("funcode", funCodeFieldList);

            // 数据长度
            byte[] datlbyte = data.Skip(currentCursor).Take(2).ToArray();
            currentCursor = currentCursor + 2;
            CodeField lenField = new CodeField
            {
                code = "datalength",
                value = datlbyte
            };
            List<CodeField> lenFieldList = new List<CodeField>();
            lenFieldList.Add(lenField);
            fieldDictionary.Add("datalength", lenFieldList);

            while (currentCursor < data.Length - 2)
            {
                byte[] parabyte = data.Skip(currentCursor).Take(2).ToArray();//参数码
                currentCursor = currentCursor + 2;
                string paracode = TransForm.ByteToHexString(parabyte);

                byte[] paraLbyte = data.Skip(currentCursor).Take(2).ToArray();//参数长度
                currentCursor = currentCursor + 2;
                int paraLen = TransForm.ByteToUint8(paraLbyte);

                byte[] paravalue = data.Skip(currentCursor).Take(paraLen).ToArray(); //参数值
                currentCursor = currentCursor + paraLen;

                CodeField codeField = new CodeField
                {
                    code = paracode,
                    value = paravalue
                };

                if (fieldDictionary.ContainsKey(paracode))
                {
                    fieldDictionary[paracode].Add(codeField);
                }
                else
                {
                    fieldDictionary.Add(paracode, new List<CodeField>() { codeField });
                }
            }
            return fieldDictionary;
        }
    }
}
